package com.mar.tech.unify.handler;

import com.mar.tech.unify.http.ExtHttpStatus;
import com.mar.tech.unify.spi.BeforeHandler;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.vertx.ext.web.RoutingContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;

/**
 * Description: 限速 .<br>
 *
 * @author 孟祥元
 * @Date 2020/9/17 14:31
 */
public class RateLimitHandler implements BeforeHandler {
  private static final Logger LOGGER = LoggerFactory.getLogger(RateLimitHandler.class);
  private static final RateLimiterRegistry rateLimiterRegistry;
  private static final RateLimiter rateLimiter;

  static {
    RateLimiterConfig config = RateLimiterConfig.custom()
      // 窗口
      .limitRefreshPeriod(Duration.ofMillis(5))
      // 限速 (1000QPS)
      .limitForPeriod(5)
      // 等待时间
      .timeoutDuration(Duration.ofMillis(5))
      .writableStackTraceEnabled(false)
      .build();
    rateLimiterRegistry = RateLimiterRegistry.of(config);
    rateLimiter = rateLimiterRegistry.rateLimiter("vert.x");
  }

  public static RateLimitHandler create() {
    return new RateLimitHandler();
  }

  @Override
  public void handle(RoutingContext rc) {
    if (rateLimiter == null) {
      rc.next();
      return;
    }

    if (rateLimiter.acquirePermission()) {
      rc.next();
    } else {
      LOGGER.debug("[限速:{}/{}] - [AvailablePermissions:{}] - [WaitingThreads:{}]",
        rateLimiter.getRateLimiterConfig().getLimitForPeriod(),
        rateLimiter.getRateLimiterConfig().getLimitRefreshPeriod(),
        rateLimiter.getMetrics().getAvailablePermissions(),
        rateLimiter.getMetrics().getNumberOfWaitingThreads()
      );
      rc.fail(ExtHttpStatus.SC_RATE_LIMIT);
    }
  }
}
